﻿using DotNetExtensions.AspNet;
using Habi.Solver.Models;
using Habi.Solver.Models.Resources;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Habi.Solver.Common
{
    public class TaskContainer : Singleton<TaskContainer>
    {
        private TaskContainer()
        {
            Tasks = new Dictionary<long, ResourceTaskModel>();

            TaskDownloader.Default.OnTaskCompleted += (e) =>
            {
                ResourceContainer.Default.Update(e.Task.Id, ResourceStatus.Downloaded);
                OnTaskCompleted?.Invoke(e);
            };
            TaskDownloader.Default.OnTaskProgressChanged += (e) =>
            {
                ResourceContainer.Default.Update(e.Task.Id, ResourceStatus.Downloading);
                OnTaskProgressChanging?.Invoke(e);
            };

            TaskUploader.Default.OnTaskCompleted += (e) =>
            {
                ResourceContainer.Default.Update(e.Task.Id, ResourceStatus.Uploaded);
                OnTaskCompleted?.Invoke(e);
            };
            TaskUploader.Default.OnTaskProgressChanged += (e) =>
            {
                ResourceContainer.Default.Update(e.Task.Id, ResourceStatus.Uploading);
                OnTaskProgressChanging?.Invoke(e);
            };
        }
        
        public event TaskEvent OnTaskChanged;
        public event TaskEvent OnBeforeTaskChange;

        public event TransferTaskEvent OnTaskCompleted;
        public event TransferTaskEvent OnTaskProgressChanging;

        public Dictionary<long, ResourceTaskModel> Tasks
        {
            get; private set;
        }

        public void Add(ResourceTaskModel task, bool auto = false)
        {
            if (Tasks.ContainsKey(task.Id)) return;

            OnBeforeTaskChange?.Invoke(task);

            if (task.Status == (int)ResourceTaskStatus.Canceled) return;

            Tasks.Add(task.Id, task);

            task.Status = (int)ResourceTaskStatus.Ready;

            OnTaskChanged?.Invoke(task);

            if (auto) Start(task);
        }

        public void Add(IEnumerable<ResourceTaskModel> tasks, bool auto = false)
        {
            foreach (var item in tasks)
            {
                if (Tasks.ContainsKey(item.Id)) continue;

                Add(item, auto);
            }
        }

        public void Start(long id)
        {
            if (!Tasks.ContainsKey(id)) return;

            var task = Tasks[id];

            Start(task);
        }

        public void Start(ResourceTaskModel task)
        {
            if (!Tasks.ContainsKey(task.Id)) Add(task);

            if (task.Type == (int)TaskType.Download) TaskDownloader.Default.Start(task);
            if (task.Type == (int)TaskType.Upload) TaskUploader.Default.Start(task);
        }

        public void Pause(long id)
        {
            if (!Tasks.ContainsKey(id)) return;

            var task = Tasks[id];

            Pause(task);
        }

        public void Pause(ResourceTaskModel task)
        {
            if (!Tasks.ContainsKey(task.Id)) return;

            if (task.Type == (int)TaskType.Download) TaskDownloader.Default.Pause(task);
            if (task.Type == (int)TaskType.Upload) TaskUploader.Default.Pause(task);
        }

        public void Delete(long id)
        {
            if (!Tasks.ContainsKey(id)) return;

            var task = Tasks[id];

            Delete(task);
        }

        public void Delete(ResourceTaskModel task)
        {
            if (!Tasks.ContainsKey(task.Id)) return;

            if (task.Type == (int)TaskType.Download) TaskDownloader.Default.Delete(task);
            if (task.Type == (int)TaskType.Upload) TaskUploader.Default.Delete(task);

            Tasks.Remove(task.Id);
            OnTaskChanged?.Invoke(task);
        }

    }
}
